#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h> 
#include <linux/irq.h>
#include <linux/platform_device.h> 
#include <linux/miscdevice.h>
#include <linux/input.h>
#include <linux/i2c.h>

#define AHT10_NAME  "aht10"
#define AHT10_NUM	1
#define MESURE_CMD	0xAC
#define CRC_STAT	0x71
#define CKECK_CMD   0xE1
#define SCAN_SEC	400
#define DELAY_SEC	100

struct aht10_st
{
	int major;
	int minor;
	dev_t devID;
	int dataBuff[2];
	struct cdev cdev;
	struct class *class;
	struct device *device;
	struct i2c_client *client;
};
static struct aht10_st aht10;

static int aht10_read_regs(const struct aht10_st *dev, u8 reg, void *buf, int lenth)
{
	int ret;
	struct i2c_msg msg[2];
	struct i2c_client *client = dev->client;

	//写寄存器地址
	msg[0].addr 	= client->addr;
	msg[0].flags 	= 0;
	msg[0].buf 		= &reg;
	msg[0].len 		= 1;

	//读数据
	msg[1].addr 	= client->addr;
	msg[1].flags 	= I2C_M_RD;
	msg[1].buf 		= buf;
	msg[1].len 		= lenth;

	ret = i2c_transfer(client->adapter , msg, 2);
	if(ret ==2)
	{
		ret =0;
	}
	else
	{
		printk("aht10_read_regs error\r\n");
		return -EINVAL;
	}

	return 0;
}

static int aht10_write_regs(const struct aht10_st *dev, u8 reg, void *buf, int lenth)
{
	int ret;
	u8 sendBuff[256] ={0};
	struct i2c_msg msg;
	struct i2c_client *client = dev->client;

	sendBuff[0] = reg;
	memcpy(&sendBuff[1],buf,lenth);

	//写数据
	msg.addr 	= client->addr;
	msg.flags 	= 0;
	msg.buf 	= sendBuff;
	msg.len 	= lenth+1;

	ret = i2c_transfer(client->adapter, &msg, 1);
	if(ret ==1)
	{
		ret =0;
	}
	else
	{
		printk("aht10_write_regs error\r\n");
		return -EINVAL;
	}

	return 0;
}

static u8 aht10_read_reg(const struct aht10_st *dev, u8 reg)
{
	u8 data;

	aht10_read_regs(dev,reg,&data,1);
	
	return data;
}

static int aht10_write_reg(const struct aht10_st *dev, u8 reg, u8 data)
{
	u8 buf = data;

	return aht10_write_regs(dev, reg, &buf, 1);
}
	
static int aht10_open(struct inode *inode, struct file *flip)
{
	int ret = 0;
	u8 data = 0;
	u8 check_data[] = {0x08, 0x00};
	flip->private_data = &aht10;

	mdelay(100);
	data = aht10_read_reg(&aht10, CRC_STAT);
	if(((data>>3)&0x01) ==0)
	{
		ret = aht10_write_regs(&aht10, CKECK_CMD, check_data, sizeof(check_data));
		mdelay(100);
		data = aht10_read_reg(&aht10, CRC_STAT);
		if(((data>>3)&0x01) ==0)
		{	
			printk("aht10_open error\r\n");
			return -EINVAL;
		}
	}
	
	return 0;
}

static ssize_t aht10_read(struct file *flip, char __user *buf, size_t cnt, loff_t *off_t)
{
	int ret =0;
	u8 senddata[]  = {0x33, 0x00};
	u8 recvdata[6] = {0};
	struct aht10_st *me = flip->private_data;

	ret = aht10_write_regs(me, MESURE_CMD, senddata, sizeof(senddata));
	if(ret !=0)
	{
		printk("aht10_write_regs error\r\n");
		return -EINVAL;
	}

	mdelay(100);
	ret = aht10_read_regs(me, CRC_STAT, recvdata, 6);
	if(ret !=0)
	{
		printk("aht10_read_regs error\r\n");
		return -EINVAL;
	}
	me->dataBuff[0] = (recvdata[1]<<12) + (recvdata[2]<<4) + (recvdata[3]>>4);
	me->dataBuff[1] = ((recvdata[3]&0x0f)<<16) + (recvdata[4]<<8) + recvdata[5];

	ret = copy_to_user(buf, me->dataBuff, sizeof(me->dataBuff));
	if(ret != 0)
	{
		printk("aht10_read error! ret:%d\r\n",ret);
		return ret;
	}

	return 0;
}

static int aht10_release(struct inode *inode, struct file *flip)
{
	return 0;
}

static const struct file_operations aht10_ops=
{
	.owner 		= THIS_MODULE,
	.open 		= aht10_open,
	.read 		= aht10_read,
	.release 	= aht10_release,
};

static int aht10_probe(struct i2c_client *client, const struct i2c_device_id *dev)
{
	int ret =0;

	//获取节点
	aht10.client = client;

	//申请设备号
	if(aht10.major)
	{
		aht10.devID = MKDEV(aht10.major, 0);
		ret = register_chrdev_region(aht10.devID, AHT10_NUM, AHT10_NAME);
		if(ret <0)
			goto chrdev_err;
	}
	else
	{
		ret = alloc_chrdev_region(&aht10.devID, 0, AHT10_NUM, AHT10_NAME);
		if(ret<0)
			goto chrdev_err;
		aht10.major = MAJOR(aht10.devID);
		aht10.minor = MINOR(aht10.devID);
	}
	
	//注册字符设备
	aht10.cdev.owner = THIS_MODULE;
	cdev_init(&aht10.cdev, &aht10_ops);
	ret = cdev_add(&aht10.cdev, aht10.devID, AHT10_NUM);
	if(ret <0)
		goto cdev_err;

	//创建类
	aht10.class =  class_create(THIS_MODULE, AHT10_NAME);
	if(IS_ERR(aht10.class))
		goto class_err;
		
	//创建设备
	aht10.device = device_create(aht10.class, NULL, aht10.devID, NULL, AHT10_NAME);
	if(IS_ERR(aht10.device))
		goto device_err;

	printk("aht10_probe sucess\r\n");
	return 0;

device_err:
	class_destroy(aht10.class);
class_err:
	cdev_del(&aht10.cdev);
cdev_err:
	unregister_chrdev_region(aht10.devID, AHT10_NUM);
chrdev_err:
	return -EINVAL;
}

static int aht10_remove(struct i2c_client *client)
{
	//注销字符设备
	cdev_del(&aht10.cdev);
	unregister_chrdev_region(aht10.devID, AHT10_NUM);

	//删除设备
	device_destroy(aht10.class, aht10.devID);

	//删除类
	class_destroy(aht10.class);

	printk("aht10_remove sucess\r\n");
	return 0;
}

const struct i2c_device_id  aht10_id[] = 
{
	{"asair,aht10",0},
	{}
};

const struct of_device_id aht10_of_math[] = 
{
	{.compatible="asair,aht10"},
	{}
};

static struct i2c_driver aht10_dev = 
{
	.probe 	= aht10_probe,
	.remove = aht10_remove,
	.driver = 
	{
		.owner 			= THIS_MODULE,
		.name 			= "aht10",
		.of_match_table = aht10_of_math,
	},
	.id_table = aht10_id,
};

static int __init aht10_init(void)
{
	return i2c_add_driver(&aht10_dev);
}

static void __exit aht10_exit(void)
{
	i2c_del_driver(&aht10_dev);
}

module_init(aht10_init);
module_exit(aht10_exit);
MODULE_AUTHOR("jtb");
MODULE_LICENSE("GPL");


